package ru.ys.physics.core;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import ru.ys.physics.Function;
import ru.ys.physics.Normalizer;

import com.googlecode.fannj.Fann;

public class Main {

	private static final String LIBRARY_FILENAME = "D:/dev/projects/neural/neural-workspace/Physicist/lib/fannfloat.dll";
	private static final String ANN_FILENAME = "D:/dev/projects/neural/neural-workspace/data/physicist.ann";
	private static final String TRAINING_FILENAME = "D:/dev/projects/neural/neural-workspace/data/physicist.dat";

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		Boolean createTrainFile = false;

		List<Double[]> result = new ArrayList<Double[]>();

		Function function = new Function();

		Integer deltaTime = 5;
		Integer measuresQnt = 6;
		Integer zeroTimeDiap = 150;
		Integer trainingPairsQnt = 50;

		Double minimum = function.apply((double) 0);
		Double maximum = function.apply((double) (zeroTimeDiap + deltaTime
				* measuresQnt));

		Random random = new Random();
		Normalizer normalizer = new Normalizer();

		for (Integer counter = 0; counter < trainingPairsQnt; ++counter) {
			Integer zeroTime = random.nextInt(zeroTimeDiap);
			Double[] measures = new Double[measuresQnt];

			Integer currentTime = zeroTime;
			for (Integer i = 0; i < measuresQnt; ++i) {
				measures[i] = function.apply((double) (currentTime));
				currentTime += deltaTime;
			}

			measures = normalizer.normalize(measures, minimum, maximum);

			result.add(measures);
		}

		if (createTrainFile) {
			createTrainingFile(TRAINING_FILENAME, result);
		}

		checkAnn(ANN_FILENAME, result);

	}

	public static void checkAnn(String annFilename, List<Double[]> measures) {
		System.load(LIBRARY_FILENAME);

		Fann fann = new Fann(annFilename);

		Integer measureLength = measures.get(0).length;
		Double errorSum = 0.0;

		Integer counter;
		for (counter = 0; counter < measures.size(); ++counter) {
			float[] test = new float[measureLength - 1];
			float trueAnswer = measures.get(counter)[measures.get(0).length - 1]
					.floatValue();

			System.out.println("---" + counter + "---");
			for (Integer i = 0; i < measureLength - 1; ++i) {
				test[i] = measures.get(counter)[i].floatValue();
				System.out.print(test[i] + " ");
			}

			float annAnswer = fann.run(test)[0];
			float error = Math.abs(annAnswer - trueAnswer);
			
			System.out.println();
			System.out.println("Real answer: " + trueAnswer);
			System.out.println("Fann answer: " + annAnswer);
			System.out.println("Error value: " + error);
			
			errorSum += error;
		}

		System.out.println("Average error: " + errorSum / counter);
	}

	public static void createTrainingFile(String filename,
			List<Double[]> measures) {
		File file = new File(filename);
		if (file.exists()) {
			file.delete();
		}
		PrintWriter printWriter = null;
		try {
			printWriter = new PrintWriter(file);

			printWriter.print(measures.size() + " ");
			printWriter.print((measures.get(0).length - 1) + " ");
			printWriter.print(1);

			for (Double[] line : measures) {
				printWriter.println();
				for (int i = 0; i < line.length - 1; ++i) {
					printWriter.print(line[i] + " ");
				}
				printWriter.println();
				printWriter.print(line[line.length - 1]);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} finally {
			if (printWriter != null) {
				printWriter.close();
			}
		}
	}

}
